﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;


namespace Zero.Data.Infrastructure
{
    public abstract class RepositoryBase<T> where T : BaseEntity
    {
        private ZeroContext dataContext;
        private readonly IDbSet<T> dbset;
        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        protected ZeroContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }


        /// <summary>
        /// 获取实体
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public virtual T Get(object id)
        {
            return dbset.Find(id);
        }

        /// <summary>
        /// 获取所有实体
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<T> GetAll()
        {
            return dbset.AsQueryable();
        }

        /// <summary>
        /// 获取满足条件的实体集合
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public virtual IQueryable<T> GetMany(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).AsQueryable();
        }


        /// <summary>
        /// 根据键值获取指定实体
        /// </summary>
        /// <param name="keys"></param>
        /// <returns></returns>
        public virtual T Find(params object[] keys)
        {
            return dbset.Find(keys);
        }

        /// <summary>
        /// 根据表达式条件获取实体
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public virtual T Find(Expression<Func<T, bool>> predicate)
        {
            return dbset.FirstOrDefault(predicate);
        }

        /// <summary>
        /// 分页获取指定实体集合
        /// </summary>
        /// <param name="filter"></param>
        /// <param name="total"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public virtual IQueryable<T> GetByPage(Expression<Func<T, bool>> filter, out int total, int page, int size)
        {
            int skipCount = (page - 1) * size;
            var _resetSet = filter != null ? dbset.Where(filter).AsQueryable() : dbset.AsQueryable();
            _resetSet = skipCount == 0 ? _resetSet.Take(size) : _resetSet.Skip(skipCount).Take(size);
            total = _resetSet.Count();
            return _resetSet.AsQueryable();
        }

        /// <summary>
        /// 添加实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Add(T entity)
        {
            entity.CreateDate = DateTime.Now;
            entity.ModifyDate = DateTime.Now;
            dbset.Add(entity);
        }

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Update(T entity)
        {
            entity.CreateDate = DateTime.Now;
            entity.ModifyDate = DateTime.Now;
            dbset.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
        }

        /// <summary>
        /// 物理删除实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Remove(T entity)
        {
            dbset.Remove(entity);
        }

        /// <summary>
        /// 根据物理删除实体
        /// </summary>
        /// <param name="id">主键</param>
        public virtual void Remove(object id)
        {
            var obj = Get(id);
            dbset.Remove(obj);
        }

        /// <summary>
        /// 逻辑删除实体
        /// </summary>
        /// <param name="entity"></param>
        public virtual void Delete(T entity)
        {
            entity.IsDel = true;
            dbset.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
        }


        /// <summary>
        /// 根据主键逻辑删除实体
        /// </summary>
        /// <param name="id"></param>
        public virtual void Delete(object id)
        {
            var obj = Get(id);
            Delete(obj);
        }

        /// <summary>
        /// 逻辑删除满足条件的实体集合
        /// </summary>
        /// <param name="where"></param>
        public virtual void Delete(Expression<Func<T, bool>> where)
        {
            var objects = GetMany(where);
            foreach (T obj in objects)
                Delete(obj);
        }

        public virtual int Count
        {
            get { return dbset.Count(); }
        }
    }
}
